package org.dxy.domain.model.aggregate.impl;

import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.command.route.*;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.event.route.*;
import org.dxy.domain.event.route.RouteProcessesAssignedEvent;
import org.dxy.domain.model.aggregate.Route;
import org.dxy.domain.model.valobj.RouteId;
import org.dxy.domain.model.valobj.RouteStatusEnum;


import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @description: 工艺路线聚合根实现类
 * @author: dxy
 * @createTime: 2025/6/12 22:52
 */
@Slf4j
@Getter
@Builder
public class RouteAggRoot implements Route {
//    /** 工艺路线ID */
    private RouteId routeId;
    /** 工艺路线编码 */
    private final String routeCode;
    /** 步骤ID列表 */
    private List<Long> processStepIds;
    /** 工艺路线状态 */
    private RouteStatusEnum status;

    private final List<DomainEvent> domainEvents = new ArrayList<>();


    // === 静态工厂方法 ===
    public static Route create(Long routeId,CreateRouteCommand command) {
        RouteAggRoot route = RouteAggRoot.builder()
                .routeId(RouteId.of(routeId))
                .routeCode(command.routeCode())
                .status(RouteStatusEnum.CREATED)
                .build();

        RouteCreatedEvent event = new RouteCreatedEvent(routeId);
        // 创建并记录事件
        route.addDomainEvent(event);

        return route;
    }


    // === 事件相关方法 ===
    @Override
    public List<DomainEvent> getDomainEvents() {
        return Collections.unmodifiableList(domainEvents); // 返回一个 不可修改的视图
    }

    @Override
    public void addDomainEvent(DomainEvent event) {
        domainEvents.add(event);
    }

    @Override
    public void clearDomainEvents() {
        domainEvents.clear();
    }

    @Override
    public boolean hasDomainEvents() {
        return !domainEvents.isEmpty();
    }

    @Override
    public boolean hasNoDomainEvents() {
        return domainEvents.isEmpty();
    }



    @Override
    public void update(UpdateRouteCommand command) {
        checkNotArchived();
        this.processStepIds = new ArrayList<>(command.stepIds());
        addDomainEvent(new RouteUpdatedEvent(routeId.getValue(), processStepIds));
    }

    @Override
    public void disable(RouteDisableCommand command) {
        checkNotArchived();
        if (status == RouteStatusEnum.DISABLED) {
            throw new IllegalStateException("工艺路线已经处于禁用状态");
        }
        this.status = RouteStatusEnum.DISABLED;
        RouteDisabledEvent routeDisabledEvent = new RouteDisabledEvent(routeId.getValue());
        addDomainEvent(routeDisabledEvent);
    }

    @Override
    public void enable(RouteEnableCommand command) {
        checkNotArchived();
        if (status == RouteStatusEnum.ENABLED) {
            throw new IllegalStateException("工艺路线已经处于启用状态");
        }
        this.status = RouteStatusEnum.ENABLED;
        addDomainEvent(new RouteEnabledEvent(routeId.getValue()));
    }

    @Override
    public void assignProcesses(RouteAssignProcessesCommand command) {
        checkNotArchived();
        
        // 验证工序ID列表不能为空
        if (command.processIds() == null || command.processIds().isEmpty()) {
            throw new IllegalArgumentException("工序ID列表不能为空");
        }
        
        // 验证工序ID列表中不能有重复项
        if (command.processIds().size() != new HashSet<>(command.processIds()).size()) {
            throw new IllegalArgumentException("工序ID列表中不能有重复项");
        }
        
        log.info("为工艺路线 {} 分配工序: {}", routeId.getValue(), command.processIds());
        
        // 更新工序步骤ID列表（全量覆盖）
        this.processStepIds = new ArrayList<>(command.processIds());
        
        // 创建并发布工序分配事件
        RouteProcessesAssignedEvent event = new RouteProcessesAssignedEvent(
                routeId.getValue(),
                new ArrayList<>(command.processIds())
        );
        
        addDomainEvent(event);
        
        log.info("工艺路线 {} 工序分配完成，共分配 {} 个工序", routeId.getValue(), command.processIds().size());
    }

    @Override
    public void removeStep(RouteRemoveStepCommand command) {
        checkNotArchived();
        if (!processStepIds.contains(command.stepId())) {
            throw new IllegalArgumentException("步骤不存在");
        }
        processStepIds.remove(command.stepId());
        addDomainEvent(new RouteStepRemovedEvent(routeId.getValue(), command.stepId()));
    }

    @Override
    public void reorderSteps(RouteReorderStepCommand command) {
        checkNotArchived();
        if (new HashSet<>(this.processStepIds).equals(new HashSet<>(command.stepIds()))) {
            this.processStepIds = new ArrayList<>(command.stepIds());
            RouteStepReorderedEvent event = new RouteStepReorderedEvent(
                    routeId.getValue(),
                    processStepIds
            );
            addDomainEvent(event);
        } else {
            throw new IllegalArgumentException("步骤列表不匹配");
        }
    }

    @Override
    public void updateStep(RouteStepUpdateCommand command) {
        checkNotArchived();
        if (!processStepIds.contains(command.stepId())) {
            throw new IllegalArgumentException("步骤不存在");
        }
        addDomainEvent(new RouteStepUpdatedEvent(
            routeId.getValue(),
            command.stepId(),
            command.executorEquipmentIds(),
            command.collectionParams(),
            command.executionStrategy()
        ));
    }

    @Override
    public void publish(RoutePublishCommand command) {
        checkNotArchived();
        if (status == RouteStatusEnum.DISABLED) {
            throw new IllegalStateException("禁用状态的工艺路线不能发布");
        }
        if (processStepIds.isEmpty()) {
            throw new IllegalStateException("工艺路线没有步骤，不能发布");
        }
        addDomainEvent(new RoutePublishedEvent(routeId.getValue()));
    }

    @Override
    public void archive(RouteArchiveCommand command) {
        if (status == RouteStatusEnum.ARCHIVED) {
            throw new IllegalStateException("工艺路线已经归档");
        }
        this.status = RouteStatusEnum.ARCHIVED;
        addDomainEvent(new RouteArchivedEvent(routeId.getValue()));
    }

    @Override
    public void delete(DeleteRouteCommand command) {
        // 检查是否可以删除（只有特定状态才能删除）
        if (!canDelete()) {
            throw new IllegalStateException("当前状态的工艺路线不能删除，只有已创建、已禁用、已归档状态的工艺路线可以删除");
        }
        
        log.info("删除工艺路线: routeId={}, status={}", routeId.getValue(), status);
        
        // 发布删除事件
        addDomainEvent(new RouteDeletedEvent(routeId.getValue()));
    }

    /**
     * 检查工艺路线是否可以删除
     * 只有已创建、已禁用、已归档状态的工艺路线可以删除
     */
    private boolean canDelete() {
        return status == RouteStatusEnum.CREATED || 
               status == RouteStatusEnum.DISABLED || 
               status == RouteStatusEnum.ARCHIVED;
    }

    private String generateVersion() {
        return "V" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    }

    private void checkNotArchived() {
        if (status == RouteStatusEnum.ARCHIVED) {
            throw new IllegalStateException("工艺路线已归档，不能进行修改操作");
        }
    }

    // === 事件应用方法（用于事件溯源） ===
    
    /**
     * 应用工艺路线创建事件
     */
    public void applyCreatedEvent(RouteCreatedEvent event) {
        this.status = RouteStatusEnum.CREATED;
        // 创建事件通常在构建时已经设置了基本信息，这里可以做一些额外的初始化
        log.debug("应用工艺路线创建事件: routeId={}", event.routeId());
    }

    /**
     * 应用工艺路线更新事件
     */
    public void applyUpdatedEvent(RouteUpdatedEvent event) {
        this.processStepIds = new ArrayList<>(event.stepIds());
        log.debug("应用工艺路线更新事件: routeId={}, stepIds={}", event.routeId(), event.stepIds());
    }

    /**
     * 应用工艺路线启用事件
     */
    public void applyEnabledEvent(RouteEnabledEvent event) {
        this.status = RouteStatusEnum.ENABLED;
        log.debug("应用工艺路线启用事件: routeId={}", event.routeId());
    }

    /**
     * 应用工艺路线禁用事件
     */
    public void applyDisabledEvent(RouteDisabledEvent event) {
        this.status = RouteStatusEnum.DISABLED;
        log.debug("应用工艺路线禁用事件: routeId={}", event.routeId());
    }

    /**
     * 应用工艺路线发布事件
     */
    public void applyPublishedEvent(RoutePublishedEvent event) {
        this.status = RouteStatusEnum.PUBLISHED;
        log.debug("应用工艺路线发布事件: routeId={}", event.routeId());
    }

    /**
     * 应用工艺路线归档事件
     */
    public void applyArchivedEvent(RouteArchivedEvent event) {
        this.status = RouteStatusEnum.ARCHIVED;
        log.debug("应用工艺路线归档事件: routeId={}", event.routeId());
    }

    /**
     * 应用工艺路线工序分配事件
     */
    public void applyProcessesAssignedEvent(RouteProcessesAssignedEvent event) {
        this.processStepIds = new ArrayList<>(event.processIds());
        log.debug("应用工艺路线工序分配事件: routeId={}, processIds={}", event.routeId(), event.processIds());
    }

    /**
     * 应用工艺路线步骤添加事件
     */
    public void applyStepAddedEvent(RouteStepAddedEvent event) {
        if (this.processStepIds == null) {
            this.processStepIds = new ArrayList<>();
        }
        if (!this.processStepIds.contains(event.stepId())) {
            this.processStepIds.add(event.stepId());
        }
        log.debug("应用工艺路线步骤添加事件: routeId={}, stepId={}", event.routeId(), event.stepId());
    }

    /**
     * 应用工艺路线步骤移除事件
     */
    public void applyStepRemovedEvent(RouteStepRemovedEvent event) {
        if (this.processStepIds != null) {
            this.processStepIds.remove(event.stepId());
        }
        log.debug("应用工艺路线步骤移除事件: routeId={}, stepId={}", event.routeId(), event.stepId());
    }

    /**
     * 应用工艺路线步骤重新排序事件
     */
    public void applyStepReorderedEvent(RouteStepReorderedEvent event) {
        this.processStepIds = new ArrayList<>(event.stepIds());
        log.debug("应用工艺路线步骤重新排序事件: routeId={}, stepIds={}", event.routeId(), event.stepIds());
    }

    /**
     * 应用工艺路线步骤更新事件
     */
    public void applyStepUpdatedEvent(RouteStepUpdatedEvent event) {
        // 步骤更新事件主要是更新步骤的配置信息，不影响聚合根的核心状态
        log.debug("应用工艺路线步骤更新事件: routeId={}, stepId={}", event.routeId(), event.stepId());
    }

}